<!-- My Contents START -->
<div id="placeholder-404"></div>
<script type="text/javascript">
	// <!-- [CDATA[
	// 404 status response page with a bouncy ASCIIfied ball

	// Three.js and AsciiEffect
	PLAYGROUND.main = function() {
		$.getScript('//threejs.org/build/three.min.js').fail(function() {
			console.debug('error: failed to load Three.js');
		}).then(function() {
			// console.log('debug: Three.js loaded');
			var urls = ['//contender-x-blogger.googlecode.com/git/js/tinycolor.min.js', '//contender-x-blogger.googlecode.com/git/js/Detector.js', '//contender-x-blogger.googlecode.com/git/js/Stats.js'];
			$.when.apply(null, urls.map($.getScript)).fail(function() {
				console.debug('error: failed to load required modules for AsciiEffect.js');
			}).then(function() {
				// console.log('debug: required modules for AsciiEffect.js loaded');
				$.getScript('//contender-x-blogger.googlecode.com/git/js/AsciiEffect.js').fail(function() {
					console.debug('error: failed to load AsciiEffect.js');
				}).then(function() {
					// console.log('debug: AsciiEffect.js loaded');
					run();
				});
			});
		});

		var run = function() {
			var container, stats;

			var camera, scene, renderer;

			var sphere_r;
			var sphere, plane;

			var anim_w_percent;
			var anim_h_percent;
			var width;
			var height;

			var start = Date.now();

			function revAnim() {
				init();
				animate();
			}

			if (document.body == undefined) {
				// animation should wait until...
				PLAYGROUND.addEvent(window, 'load', function() {
					revAnim();
				});
			} else {
				// animation now
				revAnim();
			}

			function calcWidthHeight() {
				anim_w_percent = 0.6;
				anim_h_percent = 0.8;
				var oldWidth = container.offsetWidth, oldHeight = window.innerHeight;

				// width = window.innerWidth * anim_w_percent || 2;
				// height = window.innerHeight * anim_h_percent || 2;
				width = container.offsetWidth * anim_w_percent || 2;
				// height = container.innerHeight * anim_h_percent || 2;
				height = Math.max(Math.min(400, window.innerHeight * anim_h_percent), 2);

				// should container be resized?
				return oldWidth != width || oldHeight != height;
			}

			function init() {
				container = document.getElementById('placeholder-404');

				if (calcWidthHeight()) {
					container.style.height = height + 'px';
				}

				// A click trap against #placeholder-404 (#placeholder-404
				// element must have a 'style.position' value other than
				// 'static' for this click trap to work)
				var clicktrap = document.createElement('div');
				clicktrap.className = 'clicktrap';
				container.appendChild(clicktrap);

				var info = document.createElement('div');
				info.className = 'info';
				info.innerHTML = '<h1>404 Page Not Found</h1><p><a href=\'/\'>Home</a></p>';
				var info_block = document.createElement('div');
				info_block.className = 'center-hack';
				info_block.appendChild(info);
				container.appendChild(info_block);

				// Prepare a camera, defining viewport and metrics
				camera = new THREE.PerspectiveCamera(70, width / height, 1, 1000);
				camera.position.y = 150;
				camera.position.z = 600;

				scene = new THREE.Scene();

				// Instanciate 2 lights
				var light = new THREE.PointLight(0xffffff);
				light.position.set(500, 500, 500);
				scene.add(light);
				light = new THREE.PointLight(0xffffff, 0.25);
				light.position.set(-500, -500, -500);
				scene.add(light);

				// A sphere
				sphere_r = 200;
				sphere = new THREE.Mesh(new THREE.SphereGeometry(sphere_r, 20, 10), new THREE.MeshLambertMaterial({
					shading : THREE.FlatShading
				}));
				scene.add(sphere);

				// A plane
				plane = new THREE.Mesh(new THREE.PlaneGeometry(5 * sphere_r, 2 * sphere_r), new THREE.MeshBasicMaterial({
					color : 0xe0e0e0
				}));
				plane.position.y = -sphere_r;
				plane.rotation.x = -Math.PI / 2;
				scene.add(plane);

				// Create a canvas element where the scene are rendered.
				if (Detector.webgl) {
					renderer = new THREE.WebGLRenderer({
						antialias : true, // to get smoother output
						preserveDrawingBuffer : true // to allow screenshot
					});
					renderer.setClearColor(0x000000, 0);
				} else {
					renderer = new THREE.CanvasRenderer();
				}
				renderer.setSize(width, height);
				renderer.domElement.className = 'anim';
				var render_block = document.createElement('div');
				render_block.className = 'center-hack';
				render_block.appendChild(renderer.domElement);
				container.appendChild(render_block);

				effect = new THREE.AsciiEffect(container, renderer, /*' CGO08@'*/' .,:;=|iI+hHOE#`$', {
					alpha : true, /* very slow */
					color : true, /* slow */
					block : true, /* fast */
					invert : false,
					strResolution : 'low',
					renderStyle : 'canvas'
				});
				// effect.setSize(width, height);
				// effect.domElement.className = 'anim';
				// var effect_block = document.createElement('div');
				// effect_block.className = 'center-hack';
				// effect_block.appendChild(effect.domElement);
				// container.appendChild(effect_block);

				// Rendering infomation
				stats = new Stats();
				stats.domElement.style.position = 'absolute';
				stats.domElement.style.top = '0px';
				container.appendChild(stats.domElement);

				PLAYGROUND.addEvent(window, 'resize', onWindowResize);

			}

			function onWindowResize() {
				if (calcWidthHeight()) {
					container.style.height = height + 'px';

					camera.aspect = width / height;
					camera.updateProjectionMatrix();

					renderer.setSize(width, height);
					// effect.setSize(width, height);
				}
			}

			function animate() {
				requestAnimationFrame(animate);
				render();
				stats.update();
			}

			function render() {
				var timer = Date.now() - start;

				sphere.position.y = Math.abs(Math.sin(timer * 0.002)) * 300;
				sphere.rotation.x = timer * 0.0003;
				sphere.rotation.z = timer * 0.0002;

				renderer.render(scene, camera);
				// effect.render(scene, camera);
			}

		};
	};

	// ]] -->
</script>
<!-- My Contents END -->
